package com.peanut.baby.uploader;

import android.text.TextUtils;

import com.netease.cloud.nos.android.core.CallRet;
import com.netease.cloud.nos.android.core.Callback;
import com.netease.cloud.nos.android.core.UploadTaskExecutor;
import com.netease.cloud.nos.android.core.WanAccelerator;
import com.netease.cloud.nos.android.core.WanNOSObject;
import com.netease.cloud.nos.android.exception.InvalidParameterException;
import com.peanut.baby.InitManager;
import com.peanut.baby.http.BaseObserver;
import com.peanut.baby.http.BaseResponse;
import com.peanut.baby.http.BaseScheduler;
import com.peanut.baby.http.RetrofitClient;
import com.peanut.baby.model.UploadConf;
import com.peanut.devlibrary.util.FileUtil;
import com.peanut.devlibrary.util.JsonUtils;
import com.peanut.devlibrary.util.MathUtil;
import com.peanut.devlibrary.util.StringUtil;
import com.peanut.devlibrary.util.TimeUtil;
import com.tencent.mars.xlog.Log;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.util.List;

import io.reactivex.Observable;

import static android.R.attr.path;

/**
 * Created by anonymouslystudio on 2017/6/8.
 */

public class UploadMgr {
    private static final String TAG = UploadMgr.class.getSimpleName();
    public static final int UPLOAD_TYPE_AVATAR  = 1;
    public static final int UPLOAD_TYPE_MOMENT  = 2;
    public static final int UPLOAD_TYPE_LIVE    = 3;
    public static final int UPLOAD_TYPE_QA      = 4;
    public static final int UPLOAD_TYPE_RECORD  = 5;

    private UploadMgr(){

    }
    private static final class SingleInstanceHolder{
        public static final UploadMgr UploadMgr = new UploadMgr();
    }

    public static UploadMgr getInstance(){
        return SingleInstanceHolder.UploadMgr;
    }


    public void uploadImage(String path, int uploadType, String userIdentity, final UploadListener listener) {
        if (StringUtil.isNullOrEmpty(path)) {
            Log.i(TAG, "upload failed,target file not exists " + path);
            if (listener != null) {
                listener.onUploadFailed(null, "所选文件不存在");
            }
            return;
        }

        final UploadBean taskBean = formatTaskBean(path, uploadType, userIdentity);
        Observable observable = RetrofitClient.getInstance().getUploadToken(taskBean.bucketName, InitManager.getInstance().getUser().userToken);
        observable.compose(BaseScheduler.<BaseResponse<List<UploadConf>>>compose()).subscribe(new BaseObserver<List<UploadConf>>() {
            @Override
            protected void onHandleSuccess(List<UploadConf> o) {
                onUploadTokenGet(taskBean, o, listener);
            }

            @Override
            protected void onHandleError(String code,String msg) {
                if (listener != null) {
                    listener.onUploadFailed(null, "获取上传凭证失败 " + msg);
                }
            }

        });
    }

     public void reUploadImage(final UploadConf failedConfig, final UploadListener listener){
        if(failedConfig == null || StringUtil.isNullOrEmpty(failedConfig.uploadToken)){
            Log.i(TAG,"upload failed,target file not exists "+path);
            if(listener != null){
                listener.onUploadFailed(null,"上传凭证失效");
            }
            return;
        }

        WanNOSObject wanNOSObject = new WanNOSObject();
        wanNOSObject.setNosBucketName(failedConfig.bucketName);
        wanNOSObject.setNosObjectName(failedConfig.fileInBucketName);
        if(failedConfig.localPath.endsWith("amr")){
            wanNOSObject.setContentType("audio/AMR");    // 请根据实际情况设置正确的MIME-TYPE
        }else{
            wanNOSObject.setContentType("image/jpeg");    // 请根据实际情况设置正确的MIME-TYPE
        }

        wanNOSObject.setUploadToken(failedConfig.uploadToken);

        //如果要支持断点续传或者crash后断点重传，需要持久化<filePath,uploadContext>，以SharedPreferences为例
        //SharedPreferences mPerferences = getDefaultPreferences(context);
        //String uploadContext = mPerferences.getString(file.getAbsolutePath(), null);
        String uploadContext = null;

        File f = new File(failedConfig.localPath);
        try {
            final UploadTaskExecutor executor = WanAccelerator.putFileByHttp(
                    InitManager.getInstance().getCtx(),                // 把当前Activity传进来
                    f, // 待上传文件对象
                    f.getAbsolutePath(),                                 // 在onUploadContextCreate和onProcess被回调的参数
                    // 如果支持断点续传，需要把待上传对象路径传过去
                    // 以便onUploadContextCreate更新
                    uploadContext,                        // 上传上下文，用于断点续传
                    wanNOSObject,                         // 上传对象类，里面封装了桶名、对象名、上传凭证
                    new Callback() {                      // 回调函数类，回调函数在UI线程

                        // 正常情况下只回调一次：oldUploadContext为null
                        // 当一次上传花费太长时间时UploadContext可能失效，
                        // 服务端会返回一个新的UploadContext，此时需要更新UploadContext
                        @Override
                        public void onUploadContextCreate(Object fileParam,
                                                          String oldUploadContext,
                                                          String newUploadContext) {
                            Log.d(TAG,"onUploadContextCreate "+oldUploadContext+" "+newUploadContext);


                            //如果要支持断点续传或者crash后断点重传
                            //SharedPreferences mPerferences =
                            //          PreferenceManager.getDefaultSharedPreferences(context);
                            // SharedPreferences.Editor mEditor = mPerferences.edit();
                            // mEditor.putString("FILE_TO_BE_UPLOADED_PATH", newUploadContext);
                            // mEditor.commit();

                        }

                        // 上传进度回调，每上传完一块就调用一次
                        // fileParam: 上传文件的相关参数
                        // current: 当前上传多少
                        // total: 文件总大小
                        @Override
                        public void onProcess(Object fileParam,
                                              long current, long total) {
                            Log.d(TAG,"onProcess "+current+" "+current);
                            if(listener != null){
                                listener.onUploadProgress(MathUtil.getProgress(current,total));
                            }
                        }


                        //上传成功回调函数: 如果要实现crash后的重传
                        //使用者需要将持久化的<filePath, uploadContext>删除
                        @Override
                        public void onSuccess(CallRet ret) {
                            Log.d(TAG,"onSuccess "+" code: "
                                    + ret.getHttpCode()
                                    + ", msg:"
                                    + ret.getResponse()
                                    + ", context:"
                                    + ret.getUploadContext()
                                    + ", param:"
                                    + ret.getFileParam());
                            failedConfig.uploadSuccess = true;
                            if(listener != null){
                                listener.onUploadSuccess(failedConfig);
                            }
                        }


                        // 上传失败回调函数: CallRet里面有具体的失败信息
                        // 使用者需要将持久化的<filePath, uploadContext>删除
                        @Override
                        public void onFailure(CallRet ret) {
                            Log.d(TAG,"onFailure "+" code: "
                                    + ret.getHttpCode()
                                    + ", msg:"
                                    + ret.getResponse()
                                    + ", context:"
                                    + ret.getUploadContext()
                                    + ", param:"
                                    + ret.getFileParam());
//                            executor = null;
                            String reason = "文件上传失败";
                            failedConfig.uploadSuccess = false;
                            try {
                                if(!StringUtil.isNullOrEmpty(ret.getResponse())){
                                    JSONObject obj = new JSONObject(ret.getResponse());
                                    reason = JsonUtils.JSONString(obj,"errorMsg");
                                }
                            } catch (JSONException e) {

                            }
                            if(listener != null){
                                listener.onUploadFailed(failedConfig,reason);
                            }
                        }


                        //上传取消回调函数: 用户可以在此处做暂停等业务
                        @Override
                        public void onCanceled(CallRet ret) {
                            Log.d(TAG,"onCanceled "+" code: "
                                    + ret.getHttpCode()
                                    + ", msg:"
                                    + ret.getResponse()
                                    + ", context:"
                                    + ret.getUploadContext()
                                    + ", param:"
                                    + ret.getFileParam());
                            failedConfig.uploadSuccess = false;
                            if(listener != null){
                                listener.onUploadFailed(failedConfig,"文件上传取消  "+ret.getCallbackRetMsg());
                            }
                        }

                    });

        } catch (InvalidParameterException e) {
            Log.d(TAG,"InvalidParameterException "+e.toString());
            failedConfig.uploadSuccess = false;
            if(listener != null){
                listener.onUploadFailed(failedConfig,"文件上传失败 "+e.toString());
            }
        }

    }

    public void uploadAudio(String path, int uploadType, String userIdentity, final UploadListener listener){
        if(StringUtil.isNullOrEmpty(path)){
            Log.i(TAG,"upload failed,target file not exists "+path);
            if(listener != null){
                listener.onUploadFailed(null,"所选文件不存在");
            }
            return;
        }

        final UploadBean taskBean = formatTaskBean(path,uploadType,userIdentity);
        Observable observable = RetrofitClient.getInstance().getUploadToken(taskBean.bucketName, InitManager.getInstance().getUser().userToken);
        observable.compose(BaseScheduler.<BaseResponse<List<UploadConf>>>compose()).subscribe(new BaseObserver<List<UploadConf>>() {
            @Override
            protected void onHandleSuccess(List<UploadConf> o) {
                onUploadTokenGet(taskBean,o,listener);
            }

            @Override
            protected void onHandleError(String code,String msg) {
                if(listener != null){
                    listener.onUploadFailed(null,"获取上传凭证失败 "+msg);
                }
            }

        });

    }

    /**
     *
     * @param bean
     */
    private void onUploadTokenGet(final UploadBean bean,List<UploadConf> confs,final UploadListener listener){

        if(confs == null || confs.isEmpty() || TextUtils.isEmpty(confs.get(0).uploadToken)){
            if(listener != null){
                listener.onUploadFailed(null,"解析上传凭证失败");
            }
            return;
        }

       final UploadConf config = confs.get(0);
        config.localPath = bean.path;

        Log.d(TAG,"bean: "+bean.toString());
        Log.d(TAG,"confs.get(0) "+confs.get(0).toString());



        WanNOSObject wanNOSObject = new WanNOSObject();
        wanNOSObject.setNosBucketName(confs.get(0).bucketName);
        wanNOSObject.setNosObjectName(confs.get(0).fileInBucketName);
        if(bean.path.endsWith("amr")){
            wanNOSObject.setContentType("audio/AMR");    // 请根据实际情况设置正确的MIME-TYPE
        }else{
            wanNOSObject.setContentType("image/jpeg");    // 请根据实际情况设置正确的MIME-TYPE
        }

        wanNOSObject.setUploadToken(confs.get(0).uploadToken);

        //如果要支持断点续传或者crash后断点重传，需要持久化<filePath,uploadContext>，以SharedPreferences为例
        //SharedPreferences mPerferences = getDefaultPreferences(context);
        //String uploadContext = mPerferences.getString(file.getAbsolutePath(), null);
        String uploadContext = null;

        File f = new File(bean.path);
        try {
            final UploadTaskExecutor executor = WanAccelerator.putFileByHttp(
                    InitManager.getInstance().getCtx(),                // 把当前Activity传进来
                    f, // 待上传文件对象
                    f.getAbsolutePath(),                                 // 在onUploadContextCreate和onProcess被回调的参数
                    // 如果支持断点续传，需要把待上传对象路径传过去
                    // 以便onUploadContextCreate更新
                    uploadContext,                        // 上传上下文，用于断点续传
                    wanNOSObject,                         // 上传对象类，里面封装了桶名、对象名、上传凭证
                    new Callback() {                      // 回调函数类，回调函数在UI线程

                        // 正常情况下只回调一次：oldUploadContext为null
                        // 当一次上传花费太长时间时UploadContext可能失效，
                        // 服务端会返回一个新的UploadContext，此时需要更新UploadContext
                        @Override
                        public void onUploadContextCreate(Object fileParam,
                                                          String oldUploadContext,
                                                          String newUploadContext) {
                           Log.d(TAG,"onUploadContextCreate "+oldUploadContext+" "+newUploadContext);


                            //如果要支持断点续传或者crash后断点重传
                            //SharedPreferences mPerferences =
                            //          PreferenceManager.getDefaultSharedPreferences(context);
                            // SharedPreferences.Editor mEditor = mPerferences.edit();
                            // mEditor.putString("FILE_TO_BE_UPLOADED_PATH", newUploadContext);
                            // mEditor.commit();

                        }

                        // 上传进度回调，每上传完一块就调用一次
                        // fileParam: 上传文件的相关参数
                        // current: 当前上传多少
                        // total: 文件总大小
                        @Override
                        public void onProcess(Object fileParam,
                                              long current, long total) {
                            Log.d(TAG,"onProcess "+current+" "+current);
                            if(listener != null){
                                listener.onUploadProgress(MathUtil.getProgress(current,total));
                            }
                        }


                        //上传成功回调函数: 如果要实现crash后的重传
                        //使用者需要将持久化的<filePath, uploadContext>删除
                        @Override
                        public void onSuccess(CallRet ret) {
                            Log.d(TAG,"onSuccess "+" code: "
                                    + ret.getHttpCode()
                                    + ", msg:"
                                    + ret.getResponse()
                                    + ", context:"
                                    + ret.getUploadContext()
                                    + ", param:"
                                    + ret.getFileParam());
                            config.uploadSuccess = true;
                            if(listener != null){
                                listener.onUploadSuccess(config);
                            }
                        }


                        // 上传失败回调函数: CallRet里面有具体的失败信息
                        // 使用者需要将持久化的<filePath, uploadContext>删除
                        @Override
                        public void onFailure(CallRet ret) {
                            Log.d(TAG,"onFailure "+" code: "
                                    + ret.getHttpCode()
                                    + ", msg:"
                                    + ret.getResponse()
                                    + ", context:"
                                    + ret.getUploadContext()
                                    + ", param:"
                                    + ret.getFileParam());
//                            executor = null;
                            String reason = "文件上传失败";
                            config.uploadSuccess = false;
                            try {
                                if(!StringUtil.isNullOrEmpty(ret.getResponse())){
                                    JSONObject obj = new JSONObject(ret.getResponse());
                                    reason = JsonUtils.JSONString(obj,"errorMsg");
                                }
                            } catch (JSONException e) {

                            }
                            if(listener != null){
                                listener.onUploadFailed(config,reason);
                            }
                        }


                        //上传取消回调函数: 用户可以在此处做暂停等业务
                        @Override
                        public void onCanceled(CallRet ret) {
                            Log.d(TAG,"onCanceled "+" code: "
                                    + ret.getHttpCode()
                                    + ", msg:"
                                    + ret.getResponse()
                                    + ", context:"
                                    + ret.getUploadContext()
                                    + ", param:"
                                    + ret.getFileParam());
                            config.uploadSuccess = false;
                            if(listener != null){
                                listener.onUploadFailed(config,"文件上传取消  "+ret.getCallbackRetMsg());
                            }
                        }

                    });

        } catch (InvalidParameterException e) {
            Log.d(TAG,"InvalidParameterException "+e.toString());
            config.uploadSuccess = false;
            if(listener != null){
                listener.onUploadFailed(config,"文件上传失败 "+e.toString());
            }
        }
    }

    /**
     *
     * @param paths
     */
    public void upload(List<String> paths,int uploadType){
        if(paths == null || paths.isEmpty()){
            return;
        }
        doUpload(paths,0);
    }

    /**
     *
     * @param paths
     * @param index
     */
    private void doUpload(final List<String> paths, final int index){

//        UploadManager manager = new UploadManager();
//        manager.put(paths.get(index), null, uploadToken,new UpCompletionHandler() {
//            @Override
//            public void complete(String key, ResponseInfo info, JSONObject response) {
//                //TODO
//                if(index < paths.size() - 1){
//                    doUpload(paths,index+1);
//                }
//            }
//        },null);
    }

    /**
     *  get upload token from server
     */
    private void queryUploadToken(UploadBean bean,UploadListener listener){
//        Observable tokenTask = RetrofitClient.getInstance().getUploadToken(bean.bucketName,)

    }


    /**
     *
     * @param path
     * @param type
     * @param userIdentity
     * @return
     */
    private UploadBean formatTaskBean(String path,int type,String userIdentity){
        UploadBean bean = new UploadBean();
        String fileName = FileUtil.getNameByUrl(path);
        bean.path = path;

        String result = "android_";
        switch (type){
            case UPLOAD_TYPE_AVATAR:
                result += "avatar_";
                break;
            case UPLOAD_TYPE_MOMENT:
                result += "bbs_";
                break;
            case UPLOAD_TYPE_LIVE:
                result += "live_";
                break;
            case UPLOAD_TYPE_QA:
                result += "qa_";
                break;
            case UPLOAD_TYPE_RECORD:
                result += "record_";
                break;
            default:
                result += "unknowtype_";
                break;
        }
        if(StringUtil.isNullOrEmpty(userIdentity)){
            result = result+"anonymously_";
        }else{
            result = result + userIdentity+"_";
        }
        result += TimeUtil.getCurrentSystemFormattedTime() + fileName;
        Log.d(TAG,"result file name: "+result);
        bean.bucketName = result;
        bean.status = UploadBean.STATUS_WAITING;

        return bean;
    }


    /**
     * this interface represents all status of upload task
     */
    public interface UploadListener{
        void onQueryToken();
        void onStartUpload();
        void onUploadProgress(int percent);
        void onUploadSuccess(UploadConf config);
        void onUploadFailed(UploadConf config, String failed);
    }

    public static void main(String[] args){
//        long expires = System.currentTimeMillis() / 1000 + 3600 * 24 * 30 * 12 * 10;
//
//        try {
//            final String token = Util.getToken(BUCKET, f.getName(), expires,
//                    accessKey, secretKey);


    }

}
